package util

import (
	"bytes"
	"compress/gzip"
	"compress/zlib"
	"crypto/aes"
	"crypto/cipher"
	"crypto/md5"
	"encoding/hex"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"time"
)

// AESDecrypt 使用 AES-ECB 模式解密数据
func AESDecrypt(ciphertext []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}

	if len(ciphertext)%block.BlockSize() != 0 {
		return nil, errors.New("ciphertext is not a multiple of the block size")
	}

	mode := NewECBDecrypter(block)
	mode.CryptBlocks(ciphertext, ciphertext)

	return unpad(ciphertext), nil
}

// ECBDecrypter 结构体
type ECBDecrypter struct {
	B         cipher.Block
	BlockSize int
}

// NewECBDecrypter 创建 ECB 解密器
func NewECBDecrypter(b cipher.Block) *ECBDecrypter {
	return &ECBDecrypter{b, b.BlockSize()}
}

// CryptBlocks 执行块加解密
func (x *ECBDecrypter) CryptBlocks(dst, src []byte) {
	if len(src)%x.BlockSize != 0 {
		panic("src length is not a multiple of block size")
	}
	for len(src) > 0 {
		x.B.Decrypt(dst[:x.BlockSize], src[:x.BlockSize])
		src = src[x.BlockSize:]
		dst = dst[x.BlockSize:]
	}
}

// unpad 去除 PKCS#7 填充
func unpad(data []byte) []byte {
	length := len(data)
	padding := int(data[length-1])
	return data[:(length - padding)]
}

// decompress 使用 zlib 或 gzip 解压缩数据
func Decompress(data []byte) ([]byte, error) {
	reader := bytes.NewReader(data)
	r, err := zlib.NewReader(reader)
	if err != nil {
		// 尝试使用 gzip 解压
		reader.Seek(0, 0)
		r, err = gzip.NewReader(reader)
		if err != nil {
			return nil, err
		}
	}
	defer r.Close()
	return ioutil.ReadAll(r)
}

// GenerateMD5 md5(十三位时间戳 + 六位随机数 + 业务id + 用户id)
func GenerateMD5(businessID string, userID string) string {
	// 生成一个13位的时间戳
	timestamp := time.Now().UnixNano() / int64(time.Millisecond) // 获取当前时间的毫秒数
	timestampStr := fmt.Sprintf("%013d", timestamp)              // 转换为字符串并确保是13位

	// 生成一个六位的随机数
	rand.Seed(time.Now().UnixNano())
	randomNum := rand.Intn(999999)                 // 生成一个随机数
	randomNumStr := fmt.Sprintf("%06d", randomNum) // 转换为字符串并确保是6位

	// 拼接字符串
	input := timestampStr + randomNumStr + businessID + userID

	// 计算 MD5 哈希值
	hasher := md5.New()
	hasher.Write([]byte(input))
	hash := hasher.Sum(nil)

	// 转换为十六进制字符串
	return hex.EncodeToString(hash)
}
